序言
应用程序的安全性通常体现在三个方面:
- 认证:认证是确认某主体在某系统中是否合法、可用的过程。这里的主体既可以是登录系统的用户,也可以是接入的设备或者其他系统
- 授鉴权: 授权是指当主体通过认证之后,赋予主体对应权限,鉴权是判断是否允许主体执行某项操作的过程
- 防护:防护是指系统对不法攻击的抵御能力
作为 Java 开发,要想使应用具备以上特性,你当然可以自己实现一套框架,但是技术发展这么多年,市面上应当已存在了成熟的框架,我们又为何要自己去造轮子呢?
本文将带你了解 Spring Security,通过它将使我们更便捷地实现安全性功能。
Spring Security 是什么?
Spring Security 是一个强大的、高度可定制的身份验证和访问控制框架,其关注于为 Java 应用程序提供身份验证和授权。
像所有 Spring 项目一样,Spring Security 的真正威力在于它可以如何轻松地扩展以满足定制需求。
为何选择 Spring Security ?
安全框架新增种类繁多,但仍有令人信服的理由让你选择 Spring Secutiry,因为其:
- 支持绝大多数认证机制,比如:
- HTTP BASIC authentication headers:一个基于 IETF RFC 的标准
- HTTP Digest authentication headers:一个基于 IETF RFC 的标准
- HTTP X.509 client certificate exchange:一个基于 IETF RFC 的标准
- LDAP:一种常见的跨平台身份验证方式
- Form-based authentication:用于简单的用户界面需求
- OpenID authentication:一种去中心化的身份认证方式
- Authentication based on pre-established request headers:类似于 Computer Associates SiteMinder, 一种用户身份验证及授权的集中式安全基础方案。
- Jasig Central Authentication Service:单点登录方案
- Transparent authentication context propagation for Remote Method Invocation(RMI)and HttpInvoker:一个Spring远程调用协议
- Automatic “remember-me” authentication:允许在指定到期时间前自行重新登录系统
- Anonymous authentication:允许匿名用户使用特定的身份安全访问资源
- Run-as authentication:允许在一个会话中变换用户身份的机制
- Java Authentication and Authorization Service:JAAS,Java 验证和授权 API
- Java EE container authentication:允许系统继续使用容器管理这种身份验证方式
- Kerberos:一种使用对称密钥机制,允许客户端与服务器相互确认身份的认证协议
- 防护性强,提供会话固定,点击劫持,跨站点请求伪造攻击解决方案
- 易集成,作为 Spring 家族成员,可与 Servlet API、Spring Web MVC 无缝集成
如何使用 Spring Secutiry?
快速入门——默认的 HTTP 认证
既然 Spring Secutiry 这么强大,那我们就来学会如何使用它吧!
Spring Security 使用步骤如下:
- ① 创建 Spring Boot 项目
- ② 添加相关 Spring Secutiry 依赖到 pom.xml 文件
- ③ 启动项目
① 创建 Spring Boot 项目
略。
② 添加相关 Spring Secutiry 依赖到 pom.xml 文件
1 | <!-- Spring Security --> |
③ 启动项目访问相关端口
在引入 Spring Security 项目之后,虽然没有进行任何相关的配置或编码,但 Spring Security 有一个默认的运行状态,要求在经过 HTTP 基本认证后才能访问对应的 URL 资源,因此会出现这么一个界面:

默认使用的用户名为 user, 密码则是动态生成并打印到控制台的一串随机码。
当然,以上参数值是可以修改的,可以在配置文件新增以下配置:1
2spring.security.user.name=root
spring.security.user.password=123456
重新启动应用,通过变更后的配置可以通过认证。
进阶—— URL 安全策略
虽然在快速入门中我们学会了 Spring Security 的基本使用,但一般情况下 URL 是通过 RBAC(Role-based access control,基于角色的访问控制)进行控制的,因此,在 Spring Security 中,也定义了相关的 URL 安全策略。
从快速入门中,我们知道默认情况下的 Spring Security 会拦截所有请求,那么如何进行自定义呢。
自定义安全策略
对于安全策略,Spring Security 中肯定存在了一个相应的类包含安全策略相关方法,那么我们找到该类重写它的方法就行了。
因此若想自定义安全策略,需要:
- 继承相应的配置类重写对应方法
- 将创建的配置类交由 Spring 管理
因此,我们首先需要在配置类上添加@EnableWebSecurity注解,使该类自动被 Spring 发现并注册。1
2
public class WebSecurityConfig extends WebSecurityConfigurerAdapter
之后,重写继承类的方法:1
2
3
4
protected void configure(HttpSecurity httpSecurity) throws Exception {
}
configure()方法继承自WebSecurityConfigurerAdapter类,其默认声明了一些安全特性:
- 验证所有请求
- 允许用户使用默认的表单页面登录进行身份验证
- 允许用户使用 HTTP 基本认证
这些安全特性我们都需要吗?应当是不需要的。
我们需要验证所有的请求吗?
不需要,一般肯定存在谁都可以访问的请求(如登录请求)。
我们需要使用默认的表单页面吗?
不需要,一般肯定是自己提供更优美的页面。
我们一定会使用 HTTP 认证这种方式进行认证吗?
不一定,一般开发者构建的系统更为复杂,那么认证流程自然得重新适配。
因此,这些安全特性允许开发者自定义,这些都通过HttpSecurity。
HttpSecurity允许我们为特定的 HTTP 请求配置安全策略,其提供了很多配置相关的方法:
authorizeRequests():返回了一个 URL 拦截注册器,可调用它提供的以下方法来对指定的 URL 指定安全策略anyRequest():对任何请求执行何种策略antMatchers():采用 ANT 模式的 URL 匹配器,在 ANT 模式中:?:表示匹配任意单个字符*:表示匹配 0 或任意数量的字符**:表示匹配 0 或者更多的目录
regexMatchers():正则模式的 URL 匹配器- ……
formLogin():声明了表单认证方式,可指定自定义的登录页面或路由
-httpBasic():csrf(): Spring Security 提供的跨站请求伪造防护功能
1 |
|
工作原理
Spring Security 设计时采用了责任链的模式,为了适配各种业务场景,通过FilterChainProxy构造了一条非常长的过滤器链,默认(Security 5.2.2 版本)过滤器包括:
WebAsyncManagerIntegrationFilter:关联 Spring Web 上下文和 Spring Security上下文SecurityContextPersistenceFilter:本次请求前构建SecurityContext对象(设置Authentication对象)到ThreadLocal中,请求后移除,方便在后续过滤器中获取授权信息HeaderWriterFilter:往请求头或响应头里写入信息CsrfFilter:跨站请求伪造安全LogoutFilter:注销相关UsernamePasswordAuthenticationFilter(重要):认证授权相关,基于表单的登录信息进行校验,成功后构造授权对象Authentication封装到SecurityContextHolder中,后续用于资源权限判断DefaultLoginPageGeneratingFilter:若未配置登录页面则系统初始化时将配置这个过滤器,前后端分离用不到BasicAuthenticationFilter:检测和处理 http basic 认证,由于该认证方式不安全,基本用不到RequestCacheAwareFilter:用来处理请求的缓存SecurityContextHolderAwareRequestFilter:主要是包装请求对象 requestAnonymousAuthenticationFilter:匿名访问相关,若检测到SecurityContextHolder中不存在Authentication对象将提供提供一个匿名Authentication。SessionManagementFilter:管理 SessionExceptionTranslationFilter:用于处理前面的认证异常AuthenticationException:和后续的资源权限异常AccessDeniedExceptionFilterSecurityInterceptor(重要):鉴权相关,判断资源是否有权访问(与配置的规则有关),将调用AccessDecisionManager来验证当前已认证成功的用户是否有权限访问该资源
当然,若需要扩展还可以进行相应的增加,Spring Security 还提供了其他过滤器,后续我们会使用。
不过现在,我们的关注点并不在此,我们最想知道的是:在 Security 中是如何完成认证、授权和鉴权的。
在 Security 中,通过两个核心的过滤器来完成以上任务:
UsernamePasswordAuthenticationFilterFilterSecurityInterceptor
具体流程,我们将在后续文章中进行分析。
参考
- Spring Security 官网
- 陈木鑫. Spring Security 实战 [M]. 电子工业出版社,2019